package tw.twandroidproj.app.network;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import com.koushikdutta.ion.Response;
import com.koushikdutta.ion.builder.Builders;
import com.orm.SugarRecord;

import tw.twandroidproj.app.model.SmsModel;
import tw.twandroidproj.app.model.*;

import java.io.File;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Frezc on 2015/11/5.
 * 单例类, 得到对象请用getInstance()方法
 */
public class NetworkManager {

    private Context context;
    private Object futureGroup = new Object();
    AuthManager manager = AuthManager.getInstance(context);

    /***
     * 一个通用的get请求方法
     * @param url 请求地址
     * @param listener 回调接口
     * @param type 泛型的Type对象, 如果是普通类 type =  (Type) MyClass.class; 带泛型(如数组) type = new TypeToken<List<MyClass>>(){}.getType();
     * @param <T> 请求得到的对象类型
     * @return
     */
    public <T> Future<?> get (String url, final OnResponseListener<T> listener, final Type type) {
        return Ion.with(context)
                .load(url)
                .group(futureGroup)
                .asString()
                .withResponse()
                .setCallback(new FutureCallback<Response<String>>() {
                    @Override
                    public void onCompleted(Exception e, Response<String> result) {
                        Gson gson = new Gson();
                        if(result==null){
                            ErrorModel errorModel_netfail=new ErrorModel();
                            errorModel_netfail.setStatus_code(-1);
                            listener.onFailed(errorModel_netfail);
                        }
                        else if (result.getHeaders().code() == 200) {
                            //todo
                            T t = gson.fromJson(result.getResult(), type);
                            listener.onSuccess(t);
                        } else {
                            listener.onFailed(gson.fromJson(result.getResult(), ErrorModel.class));
                        }
                    }
                });
    }

    /***
     * 如果返回不是数组时建议调用该函数
     * @param url 请求地址
     * @param listener 回调接口
     * @param clazz 对象对应的Class类 clazz = MyClass.class;
     * @param <T> 请求得到的对象类型
     * @return
     */
    public <T> Future<?> get (String url, OnResponseListener<T> listener, Class<T> clazz) {
        return this.get(url, listener, (Type) clazz);
}

    /**
     * 未测试, 请在测试后再使用
     * @param url
     * @param map
     * @param listener
     * @param <T>
     * @return
     */
    public <T> Future<?> postForm (String url, Map<String, String> map, OnResponseListener<T> listener){
        final Builders.Any.B request = Ion.with(context).load(url);

        for (Map.Entry<String, String> data : map.entrySet()) {
            request.setBodyParameter(data.getKey(), data.getValue());
        }

        return request.group(futureGroup).asString().withResponse()
                .setCallback(new FutureCallback<Response<String>>() {
                    @Override
                    public void onCompleted(Exception e, Response<String> result) {
                        Log.i("network", result.getResult());
                    }
                });
    }


    /**
     * 注册
     * @param

     */
    public void register (String email,String password,String nickname, OnResponseListener<String> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("email",email);
        map.put("password",password);
        map.put("nickname",nickname);
        postForm(NetParams.REGISTER, map, listener);
    }
    /**
     * 手机注册
     * @param

     */
    public void registerByPhone (String phone,String password,String nickname,String verification_code, OnResponseListener<String> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("phone",phone);
        map.put("password",password);
        map.put("nickname",nickname);
        map.put("verification_code",verification_code);
        postForm(NetParams.REGISTER_BY_PHONE, map, listener);
    }
    /**
     * 更改密码
     * @param

     */
    public void resetPassword (String phone,String password,String verification_code, OnResponseListener<String> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("phone",phone);
        map.put("password",password);
        map.put("verification_code",verification_code);
        postForm(NetParams.RESET_PASSWORD, map, listener);
    }

    /**
     * 绑定手机
     * fail(注意返回的状态码，430:手机号与验证码不符，431:验证码过期)

     */
    public void bindPhone (String phone,String verification_code, OnResponseListener<String> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("phone",phone);
        map.put("verification_code",verification_code);
        Map<String,String> map2 =new HashMap<String,String>();
        map2.put("token",manager.getToken());
        postForm(NetParams.structureQueryUrl(NetParams.BIND_PHONE, map2), map, listener);
    }

    /**
     * 发送验证邮件
     * @param

     */
    public void sendVerifyEmail (String email, OnResponseListener<String> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("email",email);
        postForm(NetParams.SEND_VERIFY_EMAIL, map, listener);
    }

    /**
     * 验证邮件
     * @param verification_code 为验证码
     *fail(注意返回的状态码，430:邮箱与验证码不符，431:验证码过期)
     */
    public void verifyEmail (String email,String verification_code, OnResponseListener<String> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("email",email);
        map.put("verification_code",verification_code);
        postForm(NetParams.VERIFY_EMAIL, map, listener);
    }

    /**
     * 绑定邮箱
     *fail(注意返回的状态码，430:邮箱与验证码不符，431:验证码过期)
     */
    public void bindEmail (String email,String verification_code, OnResponseListener<String> listener){
        if(!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();
        else {
            Map<String, String> map = new HashMap<String, String>();
            map.put("email", email);
            map.put("verification_code", verification_code);
            Map<String, String> map2 = new HashMap<String, String>();
            map2.put("token", manager.getToken());
            postForm(NetParams.structureQueryUrl(NetParams.BIND_EMAIL, map2), map, listener);
        }
    }

    /**
     * 得到验证码
     * @para
     *

     */
    public void getSmsCode (String phone, OnResponseListener<SmsModel> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("phone",phone);
        get(NetParams.GET_SMS_CODE + "?phone=" + phone, listener, SmsModel.class);
    }
    /**
     * 得到未读消息数
     * @para
     *

     */
    public void getSms_count (String token,OnResponseListener<SmsCount> listener){
        Map<String,String> map =new HashMap<String,String>();
        map.put("token",token);
        get(NetParams.SMS_NEW + "?token=" + token, listener, SmsCount.class);
    }

    /**
     * 更新用户信息
     * @param uid 当前用户的id
     * @param token
     * @param  map      包括nickname，sex，sign，birthday，location，phone等选填项目

     */
    public void userUpdate (String token,int uid, Map<String,String> map, OnResponseListener<String> listener){
        postForm(NetParams.structurePathUrl(NetParams.USER_UPDATE,String.valueOf(uid))+"?token="+token, map, listener);
    }
    /***
     * 得到用户的简历
     * @param id 某个id的简历，填了的话返回一个简历，但是返回类型都是数组,id可以为null
     * @param uid 用户的id
     * @return
     */
    public void getResumeList(String id,int uid,final OnResponseListener<Bean<Resume>> listener) {
        //todo: 检查是否登录

        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();

        else {
            //todo: 检查数据库里是否有简历的缓存
            List<Resume> resumeToSaves_list = SugarRecord.listAll(Resume.class);
            if (resumeToSaves_list.get(0)==null) {
                //todo: 如果没有缓存, get()

                Map<String, String> map = new HashMap<String, String>();
                if(id!=null) map.put("id", id);
                map.put("token", manager.getToken());
                get(NetParams.structureQueryUrl(NetParams.RESUME_URL+"/"+String.valueOf(uid)+"/resumes",map)
                        ,listener,new TypeToken<Bean<Resume>>(){}.getType());
            }
            else {
                Bean<Resume>bean=new Bean<Resume>();
                bean.setList(resumeToSaves_list);
                listener.onSuccess(bean);
            }
        }
        //如果成功调用
        //listener.onSuccess(yourResult);
        //如果失败调用
        //listener.onFailed(erroModel);
        //下面所有请求都同
    }
    /***
     * 得到用户的简历的照片
     * id为必填
     * @return
     */
    public void getResumePhoto(String id,final OnResponseListener<Bitmap> listener) {
        //todo: 检查是否登录

        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();

        else {

                Map<String, String> map = new HashMap<String, String>();
                map.put("id", id);
                map.put("token", manager.getToken());
                get(NetParams.structureQueryUrl(NetParams.RESUME_URL+"/photo", map), listener, Bitmap.class);


        }
        //如果成功调用
        //listener.onSuccess(yourResult);
        //如果失败调用
        //listener.onFailed(erroModel);
        //下面所有请求都同
    }


    /***
     * 删除自己的某份简历
     * @param id 简历的id
     * @param listener
     */
    public void deleteResume(String id,int uid, OnResponseListener<String> listener) {
        //todo
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();

        else {
            Map<String, String> map = new HashMap<String, String>();
            map.put("id", String.valueOf(id));
            Map<String, String> map2 = new HashMap<String, String>();
            map2.put("token", manager.getToken());
            postForm(NetParams.structureQueryUrl(NetParams.RESUME_URL+"/"+String.valueOf(uid)+"/resumes"+"/"+String.valueOf(id), map2),map, listener);
        }
    }

    /**
     * 添加简历
     * @param map 除了照片等的其他属性
     * @param photo
     * @param name 简历内的角色姓名
     * @param title 简历名称
     * @param listener
     */
    public void addResume(String title,String name,int uid,Map<String, String> map, File photo, OnResponseListener<Resume> listener){
        //todo:photo还未处理
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();

        else {
            //注意查看api文档, 填上必须的参数, 这里照片并不是必须的
            map.put("name", name);
            map.put("title", title);
            Map<String, String> map2 = new HashMap<String, String>();
            map2.put("token", manager.getToken());
            postForm(NetParams.structureQueryUrl(NetParams.RESUME_URL+"/"+String.valueOf(uid)+"/resumes", map2), map, listener);
        }
    }
    /**
     * 更新简历
     * @param map 除了照片的其他属性
     * @param photo
     * @param id 简历id
     * @param listener
     */
    public void updateResume(String id, Map<String, String> map,int uid, File photo, OnResponseListener<Resume> listener){
        //todo:photo还未处理
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();

        else {
            //同上
            Map<String, String> map2 = new HashMap<String, String>();
            map2.put("token", manager.getToken());
            postForm(NetParams.structureQueryUrl(NetParams.RESUME_URL+"/"+String.valueOf(uid)+"/resumes"+"/"+String.valueOf(id), map2), map, listener);
        }
    }

    /**
    *
    * 确定申请工作，申请密码，工作id,
    * */
    public void sureApplyJob(String Job_id, String Apply_password, OnResponseListener<Job> listener) {
        if (!manager.isLogined()) {
            Toast.makeText(context, "请先登录", Toast.LENGTH_LONG).show();
        } else {
            Map<String, String> map = new HashMap<>();
            map.put("Job_id", Job_id);
            map.put("Apply_password", Apply_password);
            Map<String, String> tomap = new HashMap<>();
            tomap.put("token", manager.getToken());
            postForm(NetParams.structureQueryUrl(NetParams.SUER_APPLY_JOB, tomap), map, listener);
        }
    }

    /**
     * 更新简历
     * @param available_time 选填，可以接受的时间，默认为用户的所有空闲时间
     * @param resume_id 简历id
     * @param listener
     */
    public void publicResume(String resume_id,String available_time, OnResponseListener<Resume> listener){
        //todo:photo还未处理
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();

        else {
            Map<String, String> map = new HashMap<String, String>();
            map.put("resume_id", resume_id);
            if(available_time!=null) map.put("available_time", available_time);
            Map<String, String> tomap = new HashMap<String, String>();
            tomap.put("token", manager.getToken());
            postForm(NetParams.structureQueryUrl(NetParams.RESUME_PUBLIC_URL, tomap), map, listener);
        }
    }

    /***
     * 得到某个id的用户
     * @param id
     * @param listener
     */
    public void getUser(int id, OnResponseListener<User> listener) {
        //todo
        get(NetParams.structurePathUrl(NetParams.USER_URL, String.valueOf(id)), listener, User.class);
        //不需要缓存
    }
    /***
     * 得到所有用户
     * @param token
     * @param listener
     * @param limit
     */
public void getAllUsers(String token,int limit,OnResponseListener<Bean<User>>listener){
    Map<String,String> map=new HashMap<String, String>();
    map.put("siz",String.valueOf(limit));
    get(NetParams.USER_URL+"?token="+token,listener,new TypeToken<Bean<User>>(){}.getType());
}
    /**
     * 得到某个id的岗位
     * @param id
     * @param listener
     */
    public void getJob(int id, OnResponseListener<JobPlusTime> listener){
        //todo
        get(NetParams.structurePathUrl(NetParams.JOB_URL, String.valueOf(id)), listener, JobPlusTime.class);
        //不需要缓存
    }

    /**
     * 基本的查找岗位
     * @param keywords 关键字 空格分开
     * @param limit 最大数量
     * @param listener
     */
    public void queryJob(String keywords, int limit, OnResponseListener<Bean<Job>> listener){
        queryJob(keywords, limit, null, listener);
    }

    /**
     * 查找岗位
     * @param keywords 关键字 空格分开
     * @param limit 最大数量
     * @param other 其他参数, 可以为null, 有 orderby(*"id", "created_at", "number"), direction(*"asc", "desc"), offset(*"0", ...); 有星号的为默认
     * @param listener
     */
    public void queryJob(String keywords, int limit, Map<String, String> other, OnResponseListener<Bean<Job>> listener){
        //todo
        if (other==null)
            other=new HashMap<String, String>();
        other.put("kw",keywords);
        other.put("siz", String.valueOf(limit));
        get(NetParams.structureQueryUrl(NetParams.JOB_QUERY_URL, other), listener,new TypeToken<Bean<Job>>(){}.getType());
    }
    /**
     * 获取所有工作岗位返回主页
     */
    public void getAllJob(int limit, int offset, OnResponseListener<Bean<Job>> listener){
        getAllJob(limit,offset, null, listener);
    }

    public void  getAllJob(  int limit, int offset,Map<String, String> other,OnResponseListener<Bean<Job>>  listener){
        if (other==null)
            other=new HashMap<String, String>();
        other.put("limit",String.valueOf(limit));
        other.put("offset",String.valueOf(offset));
        get(NetParams.structureQueryUrl(NetParams.GET_ALL_JOB, other), listener, new TypeToken<Bean<Job>>() {
        }.getType());
    }
    /**
     * 申请中的岗位
     * @param other status 根据申请状态进行筛选(0:申请中，1:申请成功，2:申请失败，该项为空或其他参数表示不筛选)
     *               direction  direction(*"asc", "desc"), offset(*"0", ...); 有星号的为默认
     *               offset 查找结果的偏移量（用来分页）
     *@param   limit  最大限制
     * @param listener
     */
    public void getApplyJob( int limit, Map<String, String> other, OnResponseListener<Bean<JobApply>> listener){
        if (other==null)
            other=new HashMap<String, String>();
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();
        else{
        other.put("token",manager.getToken());
        other.put("kw", String.valueOf(limit));
        get(NetParams.structureQueryUrl(NetParams.JOB_APPLY, other), listener, new TypeToken<Bean<JobApply>>() {
        }.getType());}
    }
    /**
    * 发布岗位
    * map 里面装信息（在发布的时候直接装好）
    *
    * */
    public  void releaseJob(String name,String job_type, String salary ,String number,String description ,String pay_way, String start_at,String end_at,OnResponseListener<Job> listener){
        Map<String, String> map=new HashMap<String, String>();
        if(!manager.isLogined()){
            Toast.makeText(context,"没有登录",Toast.LENGTH_LONG).show();
        }
        else{
            map.put("token",manager.getToken());
            map.put("name",name);
            map.put("salary",salary);
            map.put("job_type",job_type);
            map.put("demanded_number",number);
            map.put("description",description);
            map.put("pay_way",pay_way);
            map.put("start_at",start_at);
            map.put("end_at",end_at);
            get(NetParams.structureQueryUrl(NetParams.RELEASE_JOB, map),listener,Job.class);
        }

    }
    /**
     * 创建申请
     * @param map job_id,申请的岗位id int
     *            resume_id 使用的简历id int
     *            description申请时的描述 String(可不填)
     * @param listener
     */
    public void postJobApply(Map<String,String> map, OnResponseListener<JobApply> listener){
        //todo:listener 的 类型！
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();
        else {
            Map<String, String> tomap = new HashMap<String, String>();
            tomap.put("token", manager.getToken());
            postForm(NetParams.structureQueryUrl(NetParams.HOST + "/jobs/" + map.get("job_id") + "/apply", tomap), map, listener);
        }
    }
    /**
     * 已完成的工作x
     * @param limit 最大数量
     * @param listener
     */
    public void completedJob( int limit, OnResponseListener<Bean<JobCompleted>> listener){
        completedJob(limit, null, listener);
    }

    /**
     * 已完成的工作
     * @param other is_evaluated 是否已评价(0:未评价, 1:已评价),direction direction(*"asc", "desc"), offset(*"0", ...); 有星号的为默认
     * @param limit 最大数量
     * @param listener
     */
    public void completedJob( int limit, Map<String,String> other, OnResponseListener<Bean<JobCompleted>> listener){
        //todo
        if (other==null)
          other=new HashMap<String, String>();
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();
        else {
            other.put("token", manager.getToken());
//          other.put("is_evaluated",String.valueOf(is_evaluated));
//          other.put("dir",String.valueOf(direction));
//          other.put("off",String.valueOf(offset));
            other.put("siz", String.valueOf(limit));
            get(NetParams.structureQueryUrl(NetParams.JOB_QUERY_URL, other), listener, new TypeToken<Bean<JobCompleted>>() {
            }.getType());
        }
    }
    /**
     * 得到岗位的评价
     * @param limit 最大数量
     * @param job_id 岗位id
     * @param listener
     */
    public void getJobEvaluated( int limit,int job_id, OnResponseListener<Bean<JobEvaluate>> listener){
        getJobEvaluated(limit, job_id, null, listener);
    }
    /**
     * 得到岗位的评价
     * @param limit 最大数量
     * @param job_id 岗位id
     * @param other offset 查找结果的偏移量（用来分页）
     * @param listener
     */
    public void getJobEvaluated( int limit,int job_id,Map<String,String> other, OnResponseListener<Bean<JobEvaluate>> listener){
        if (other==null)
            other=new HashMap<String, String>();

        other.put("job_id", String.valueOf(job_id));
        other.put("siz", String.valueOf(limit));

        get(NetParams.structureQueryUrl(NetParams.JOB_EVALUATE, other), listener, new TypeToken<Bean<JobEvaluate>>() {
        }.getType());
    }
    /**
     * 发布岗位评价
     * @param jobCompletedId 完成的岗位的id
     * @param comment 评价信息，可为null
     * @param score 评分 0-5
     * @param listener
     */
    public void postJobEvaluate(int jobCompletedId,int score,String comment, OnResponseListener<JobEvaluate> listener){
        //todo:
        Map<String,String> map=new HashMap<String, String>();
        map.put("score",String.valueOf(score));
        if (comment!=null)
        map.put("comment",comment);
        if (!manager.isLogined())
            Toast.makeText(context,"没有登录",Toast.LENGTH_SHORT).show();
        else {
            Map<String, String> tomap = new HashMap<String, String>();
            tomap.put("token", manager.getToken());
            tomap.put("job_completed_id", String.valueOf(jobCompletedId));
            postForm(NetParams.structureQueryUrl(NetParams.JOB_APPLY, tomap), map, listener);
        }
    }
    /**
     * 得到某个id的公司
     * @param id 公司id
     * @param listener
     */
    public void getCompany(int id, OnResponseListener<Company> listener){
        //todo
        get(NetParams.structurePathUrl(NetParams.COMPANY_URL, String.valueOf(id)), listener, Company.class);
    }

    /**
     * 基本的查找公司
     * @param keywords 关键字 空格分开
     * @param limit 最大数量
     * @param listener
     */
    public void queryCompany(String keywords, int limit, OnResponseListener<Bean<Company>> listener){

        queryCompany(keywords, limit, null, listener);
    }

    /**
     * 查找公司
     * @param keywords 关键字 空格分开
     * @param limit 最大数量
     * @param other 其他参数, 可以为null, 有 orderby(*"id", "created_at"), direction(*"asc", "desc"), offset(*"0", ...); 有星号的为默认
     * @param listener
     */
    public void queryCompany(String keywords, int limit, Map<String, String> other, OnResponseListener<Bean<Company>> listener){
        //todo
        if (other==null)
            other=new HashMap<String, String>();
        other.put("kw",keywords);
        other.put("siz", String.valueOf(limit));
        get(NetParams.structureQueryUrl(NetParams.COMPANY_QUERY_URL, other), listener, new TypeToken<Bean<Company>>() {
        }.getType());
    }

    /***
     * 上传头像
     * @param avatar
     */
    public void uploadAvatar(File avatar, final OnResponseListener<String> listener) {
        //todo
        //注意要检查登录并且得到token
        //检查文件的存在和类型
        if(!manager.isLogined())
            Toast.makeText(context,"用户不存在，请登录！",Toast.LENGTH_SHORT).show();
        else {
            if (!avatar.exists())
                Toast.makeText(context,"文件不存在！",Toast.LENGTH_SHORT).show();

            if (avatar.getName().substring(avatar.getName().lastIndexOf("." + 1)).compareTo("jpg")!=0||(avatar.getName().substring(avatar.getName().lastIndexOf("." + 1)).compareTo("png")!=0))
                Toast.makeText(context,"文件应为png或jpg格式！",Toast.LENGTH_SHORT).show();

            else {
                Map<String,String> step1=new HashMap<String, String>();
                step1.put("token",manager.getToken());
                Ion.with(context)
                        .load(NetParams.structureQueryUrl(NetParams.AVATAR_URL, step1))
                        .setMultipartFile("avatar", "image/" + avatar.getName().substring(avatar.getName().lastIndexOf("." + 1)), avatar)
                        .asString()
                        .withResponse()
                        .setCallback(new FutureCallback<Response<String>>() {
                            @Override
                            public void onCompleted(Exception e, Response<String> result) {
                                Gson gson = new Gson();
                                if (result.getHeaders().code() == 200) {
                                    //todo
                                    String t = gson.fromJson(result.getResult(), String.class);
                                    listener.onSuccess(t);
                                } else {
                                    listener.onFailed(gson.fromJson(result.getResult(), ErrorModel.class));
                                }
                            }
                        });
            }
        }
    }


    /***
     * 取消所有请求
     */
    public void cancel() {
        Ion.getDefault(context).cancelAll(futureGroup);
    }


    private volatile static NetworkManager instance;

    private NetworkManager(Context context) {
        this.context = context.getApplicationContext();
    }

    public static NetworkManager getInstance(Context context) {
        if (instance == null){
            synchronized (NetworkManager.class) {
                if (instance == null){
                    instance = new NetworkManager(context);
                }
            }
        }
        return instance;
    }


}
